/*
 * JSmex.java
 *
 * Created on 24. Oktober 2006, 09:58
 *
 *  This file is part of JSmex.
 *
 *  JSmex is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  JSmex is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Foobar; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package jsmex;

import java.util.Date;
import jsmex.cardservice.GlobalPlatformCardService;
import jsmex.cardservice.GsmCardService;
import jsmex.cardservice.GeldkarteCardService;
import jsmex.cardservice.MRTDCardService;
import jsmex.function.ExplorerFunctions;
import jsmex.function.GeldkarteFunctions;
import jsmex.function.GpFunctions;
import jsmex.function.GsmFunctions;
import jsmex.function.MRTDFunctions;
import opencard.core.service.SmartCard;
import opencard.core.util.OpenCardPropertyLoadingException;
import opencard.core.service.CardServiceException;
import opencard.core.terminal.CardTerminalException;
import opencard.core.event.EventGenerator;
import opencard.core.event.CTListener;
import opencard.core.event.CardTerminalEvent;
import opencard.core.service.CardRequest;

import jsmex.gui.CardInfoGUI;



/**
 *
 * @author Tobias Senger (jsmex@t-senger.de)
 */
public class JSmex implements CTListener {
    
    private LogTracer ltracer;
    
    private jsmex.cardservice.JSmexCardService jsmexcs;
    
    private boolean gsmAvailable = false;
    private boolean gkAvailable = false;
    private boolean pkcs15Available = false;
    private boolean appAvailable = false;
    private boolean jsmexAvailable = false;
    private boolean usimAvailable = false;
    private boolean gpAvailable = false;
    private boolean mrtdAvailable = false;
    
    private CardInfoGUI cigui;
    
    private ExplorerFunctions exfunc = null;
    private GeldkarteFunctions gkfunc = null;
    private GsmFunctions gsmfunc = null;
    private GpFunctions gpfunc = null;
    private MRTDFunctions mrtdfunc = null;
    
    public JSmex() {
        
        ltracer = new LogTracer("jsmex.log");
        ltracer.info("JSmex is going to be initialized.",this);
        startGUI();
        
        try { SmartCard.start(); } catch (OpenCardPropertyLoadingException e) {
            ltracer.warning("Couldn't start OpenCardFramework"+e,this);
            System.out.println(e.toString());
        } catch (CardServiceException e) {
            ltracer.warning(e.toString(),this);
            System.out.println(e.toString());
        } catch (ClassNotFoundException e) {
            ltracer.warning(e.toString(),this);
            System.out.println(e.toString());
        } catch (CardTerminalException e) {
            ltracer.warning(e.toString(),this);
            System.out.println(e.toString());
        }
        
        EventGenerator.getGenerator().addCTListener(this);
        try {
            ltracer.info("Add CardTerminal Listener.",this);
            EventGenerator.getGenerator().createEventsForPresentCards(this);
        } catch (CardTerminalException cte){
            ltracer.warning("Couldn't add CardTerminal Listener."+ cte.toString(),this);
        }
        
    }
    
    public static void main(String args[]) {
        
        new JSmex();
        
    }
    
    /**This method calls the getCardService method from the SmartCard parameter sc.
     * Then it checks which CardService was returned.
     *
     * @param sc
     */
    private void allocateServices(SmartCard sc) {
        
        ltracer.info("Start method: \"allocateServices\"",this);
        
        try {
            jsmexcs = (jsmex.cardservice.JSmexCardService) sc.getCardService(jsmex.cardservice.JSmexCardService.class, false);
            
            jsmexcs.setLogTracer(ltracer);
            ltracer.info("Following CardService was found:"+jsmexcs.getClass(),this);
            cigui.setCardStatusText("Found a known smartcard type!");
            jsmexAvailable = true;
            
            if (jsmexcs.getClass()==jsmex.cardservice.GsmCardService.class) gsmAvailable = true;
            else if (jsmexcs.getClass()==jsmex.cardservice.GeldkarteCardService.class) gkAvailable = true;
            else if (jsmexcs.getClass()==jsmex.cardservice.PKCS15CardService.class) pkcs15Available = true;
            else if (jsmexcs.getClass()==jsmex.cardservice.UsimCardService.class) usimAvailable = true;
            else if (jsmexcs.getClass()==jsmex.cardservice.GlobalPlatformCardService.class) gpAvailable = true;
            else if (jsmexcs.getClass()==jsmex.cardservice.MRTDCardService.class) mrtdAvailable = true;
        } catch (ClassNotFoundException cnfe) {
            ltracer.info("Found no suitable CardService.",this);
            jsmexAvailable = false;
        } catch (CardServiceException cse) {
            ltracer.error(cse.toString(),this);
        }
        
    }
    
    /**This method will be called when a new card was inserted into the card terminal.
     * A new CardResquest will be generated a new SmartCard instance will be created.
     * Then the method allocateServices(SmartCard sc) will be called.
     *
     * @param cte
     */
    public void cardInserted(CardTerminalEvent cte) {
        
        try {
            CardRequest cr = new CardRequest(CardRequest.ANYCARD,null,null);
            SmartCard sc = SmartCard.getSmartCard(cte, cr);
            ltracer.info("Smartcard inserted. ATR: "+opencard.core.util.HexString.hexify(sc.getCardID().getATR()),this);
            cigui.addLogText(new Date().toString()+":  Card inserted. \nATR: "+opencard.core.util.HexString.hexify(sc.getCardID().getATR())+"\n");
            
            if (sc != null) {
                cigui.setCardStatusText("Found a unknown smartcard type!");
                allocateServices(sc);
            }
            
            else {
                ltracer.warning("Did not get a SmartCard object.",this);
                SmartCard.shutdown();
            }
        } catch (CardTerminalException e) {
            ltracer.warning(e.toString(),this);
        }
        
        activateButtons();
        
    }
    
    /**When the card was removed, all GUIs will be closed except the Main-GUI
     *
     * @param cte
     */
    public void cardRemoved(CardTerminalEvent cte) {
        ltracer.info("Smartcard removed.",this);
        cigui.addLogText("card removed.");
        cigui.setCardStatusText("Please insert a smartcard.");
        deactivateButtons();
        
        gsmAvailable = false;
        gkAvailable = false;
        pkcs15Available = false;
        jsmexAvailable = false;
        gpAvailable = false;
        mrtdAvailable = false;
        
        stopGkGUI();
        stopExGUI();
        stopGsmGUI();
        stopGpGUI();
        stopMrtdGUI();
        
    }
    
    /**Creates a new CardInfoGUI instance and show the GUI.
     *
     */
    private void startGUI() {
        ltracer.info("Starting CardInfo-GUI.",this);
        cigui = new CardInfoGUI(this, jsmexcs);
        cigui.setVisible(true);
    }
    
    /**Creates a new GeldkarteFunctions instance and show the GUI.
     *
     */
    public void startGkGUI() {
        ltracer.info("Starting Geldkarte-GUI.",this);
        if (gkfunc==null) gkfunc = new GeldkarteFunctions((GeldkarteCardService)jsmexcs,ltracer);
        else gkfunc.showGUI();
    }
    
    /**Closes the Geldkarte GUI.
     *
     */
    private void stopGkGUI() {
        if (gkfunc!=null) {
            ltracer.info("Closing Geldkarte-GUI.",this);
            gkfunc.closeGUI();
            gkfunc = null;
        }
    }
    
    /**Creates a new GsmFunctions instance and show the GUI.
     *
     */
    public void startGsmGUI() {
        ltracer.info("Starting GSM-GUI.",this);
        if (gsmfunc==null) gsmfunc = new GsmFunctions((GsmCardService)jsmexcs,ltracer);
        else gsmfunc.showGUI();
    }
    
    /**Closes the GSM GUI.
     *
     */
    private void stopGsmGUI() {
        if (gsmfunc!=null) {
            ltracer.info("Closing GSM-GUI.",this);
            gsmfunc.closeGUI();
            gsmfunc = null;
        }
    }
    
    /**Creates a new GpFunctions instance and show the GUI.
     *
     */
    public void startGpGUI() {
        ltracer.info("Starting GlobalPlatform-GUI.",this);
        if (gpfunc==null) gpfunc = new GpFunctions((GlobalPlatformCardService)jsmexcs,ltracer);
        else gpfunc.showGUI();
    }
    
    /**Closes the Globalplatform GUI.
     *
     */
    private void stopGpGUI() {
        if (gpfunc!=null) {
            ltracer.info("Closing Globalplatform-GUI.",this);
            gpfunc.closeGUI();
            gpfunc = null;
        }
    }
    
    /**Creates a new ExplorerFunctions instance and show the GUI.
     *
     */
    public void startExGUI() {
        ltracer.info("Starting Explorer-GUI.",this);
        if (exfunc==null) exfunc = new ExplorerFunctions(jsmexcs,ltracer);
        else exfunc.showGUI();
    }
    
    /**Closes the Explorer GUI.
     *
     */
    private void stopExGUI() {
        if (exfunc!=null) {
            ltracer.info("Closing Explorer-GUI.",this);
            exfunc.closeGUI();
            exfunc = null;
        }
    }
    
    
    /** Activates the buttons for the founded card types
     *
     */
    private void activateButtons() {
        ltracer.info("Activating Buttons.",this);
        cigui.setGsmEnabled(gsmAvailable);
        cigui.setGkEnabled(gkAvailable);
        cigui.setPkcsEnabled(pkcs15Available);
        if (jsmexAvailable && !gpAvailable)cigui.setExplorerEnabled(true);  // no Explorer-functions for GlobalPlatform-Cards
        cigui.setAppEnabled(gpAvailable);
        if (jsmexAvailable && !mrtdAvailable)cigui.setExplorerEnabled(true);  // no Explorer-functions for  MRTDs (for now...)
        cigui.setMrtdEnabled(mrtdAvailable);
        
        
    }
    
    /**This method deactivates all Tool-Buttons.
     *
     */
    private void deactivateButtons() {
        ltracer.info("Deactivating Buttons.",this);
        cigui.setExplorerEnabled(false);
        cigui.setGsmEnabled(false);
        cigui.setGkEnabled(false);
        cigui.setAppEnabled(false);
        cigui.setPkcsEnabled(false);
        cigui.setMrtdEnabled(false);
    }

    public void startMrtdGUI() {
        ltracer.info("Starting MRTD-GUI.",this);
        if (mrtdfunc==null) mrtdfunc = new MRTDFunctions((MRTDCardService)jsmexcs, ltracer);
        else mrtdfunc.showGUI();
    }
    
    /**Closes the Explorer GUI.
     *
     */
    private void stopMrtdGUI() {
        if (mrtdfunc!=null) {
            ltracer.info("Closing MRTD-GUI.",this);
            mrtdfunc.closeGUI();
            mrtdfunc = null;
        }
    }
    
}
